<?php

namespace App\Support\CustomForm;

use Closure;

class AttributeSupport
{
    public static ?AttributeMapSupport $attributesMap = null;

    /**
     * 输入框属性name值
     *
     * @var string
     */
    protected string $inputName;

    /**
     * 输入框描述
     *
     * @var string
     */
    protected string $inputDesc;

    /**
     * 输入框类型
     *
     * @var string
     */
    protected string $inputType;

    /**
     * @var int|string|array|bool|Closure
     */
    protected $value = null;

    protected int $meanType = 0;
    protected int $projectId = 0;

    /**
     * @var array
     */
    protected array $relations = [];


    /**
     * 校验规则
     *
     * @var ValidateSupport|null
     */
    protected ?ValidateSupport $validateSupport = null;

    /**
     * 输入框自定义属性值
     *
     * @var array
     */
    protected array $customAttributes = [];

    const INPUT_TYPE_STRING          = "string";
    const INPUT_TYPE_NUMBER          = "number";
    const INPUT_TYPE_TEXT            = "textarea";
    const INPUT_TYPE_IMG             = "img";
    const INPUT_TYPE_IMG_GROUP       = "imgGroup";
    const INPUT_VIDEO                = "video";
    const INPUT_DATE_YMD             = "date-ymd";
    const INPUT_DATE                 = "date";
    const INPUT_DATETIME             = "datetime";
    const INPUT_TYPE_RADIO           = "radio";
    const INPUT_TYPE_SELECT          = "select";
    const INPUT_TYPE_SELECT_MULTIPLE = 'select-multiple'; // 下拉 - 多选框
//    const INPUT_TYPE_TABLE     = "table";
    const INPUT_TYPE_RICH_TEXT = "rich-text";
    const INPUT_TYPE_STRING_IMG_GROUP = 'string-imgGroup'; // 平铺提示（项目提示专用 文字+图片）

    /**
     * @param string $inputName
     * @param string $inputType
     * @param string $inputDesc
     */
    protected function __construct(string $inputName, string $inputType, string $inputDesc)
    {
        $this->inputName = $inputName;
        $this->inputType = $inputType;
        $this->inputDesc = $inputDesc;
    }

    /**
     * @param string $inputName
     * @param string $inputType
     * @param string $inputDesc
     * @return AttributeSupport
     */
    public static function getInstance(string $inputName, string $inputType, string $inputDesc): AttributeSupport
    {
        if (is_null(self::$attributesMap)) {
            self::$attributesMap = new AttributeMapSupport();
        }
        if (!property_exists(self::$attributesMap, $inputName)) {
            self::$attributesMap->{$inputName} = new static($inputName, $inputType, $inputDesc);
        }
        return self::$attributesMap->{$inputName};
    }

    /**
     * @param string $inputName
     * @return $this
     */
    public function setInputName(string $inputName): AttributeSupport
    {
        $this->inputName = $inputName;
        return $this;
    }

    public function getInputName(): string
    {
        return $this->inputName;
    }

    public function getInputType(): string
    {
        return $this->inputType;
    }

    public function getMeanType(): int
    {
        return $this->meanType;
    }

    /**
     * @param string $type
     * @return $this
     */
    public function setInputType(string $type = self::INPUT_TYPE_STRING): AttributeSupport
    {
        $this->inputType = $type;
        return $this;
    }

    /**
     * @param string $desc
     * @return $this
     */
    public function setInputDesc(string $desc): AttributeSupport
    {
        $this->inputDesc = $desc;
        return $this;
    }

    public function getValue()
    {
        return $this->value;
    }

    public function getCustomAttribute(): array
    {
        return $this->customAttributes;
    }

    /**
     * @param int|string|array|bool|Closure $value
     * @return $this
     */
    public function setValue($value): AttributeSupport
    {
        if ($value instanceof Closure) {
            $this->value = $value();
        } else {
            switch ($this->inputType) {
                case self::INPUT_TYPE_NUMBER:
                case self::INPUT_TYPE_STRING:
                    $this->value = $value;
                    break;
                case self::INPUT_DATE:
                case self::INPUT_DATE_YMD:
                    if (preg_match('/^\d{4}\-\d{2}\-\d{2}$/', $value) || $value == '长期有效') {
                        $this->value = $value;
                    } else {
                        $this->value = formatDateYmd($value);
                    }

                    break;
                case self::INPUT_DATETIME:
                    $this->value = formatDate($value);
                    break;
                case self::INPUT_TYPE_TEXT:
                    $this->value = $value;
                    break;
                case self::INPUT_VIDEO:
                case self::INPUT_TYPE_IMG:

                    if (is_array($value)) {
                        $this->value = array_map("picturePath", empty($value) ? [] : $value);
                    } else {
                        $this->value = picturePath($value);
                    }

                    break;

                case self::INPUT_TYPE_IMG_GROUP:
                    $this->value = array_map("picturePath", empty($value) ? [] : $value);
                    break;
                default:
                    $this->value = $value;
            }
        }
        return $this;
    }

    /**
     * @param ValidateSupport $validateSupport
     * @return $this
     */
    public function setValidateRules(ValidateSupport $validateSupport): AttributeSupport
    {
        $this->validateSupport = $validateSupport;
        return $this;
    }


    /**
     * @param mixed ...$attributes
     * @return $this
     */
    public function setCustomAttribute(array ...$attributes): AttributeSupport
    {
        foreach ($attributes as $attribute) {
            $this->customAttributes = array_merge($this->customAttributes, [
                $attribute[0] => $attribute[1]
            ]);
        }
        return $this;
    }

    /**
     * @param array $rejectOptions
     * @return $this
     */
    public function setReject(array $rejectOptions = []): AttributeSupport
    {
        return $this->setCustomAttribute(["reject", true])->setCustomAttribute([
            "rejectOptions",
            count($rejectOptions) ? $rejectOptions : ["内容需修改"]
        ]);
    }

    /**
     * @param mixed ...$attributes
     * @return $this
     */
    public function setRelations(array ...$attributes): AttributeSupport
    {
        foreach ($attributes as $attribute) {
            $this->relations = array_merge($this->relations, [
                [
                    'field' => $attribute[0],
                    'value' => $attribute[1]
                ]
            ]);
        }
        return $this;
    }

    public function setMeanType(int $meanType): self
    {
        $this->meanType = $meanType;
        return $this;
    }

    public function setProjectId(int $projectId): self
    {
        $this->projectId = $projectId;
        return $this;
    }

    /**
     * @return array
     */
    public function build(): array
    {
        return [
            "field"            => $this->inputName,
            "text"             => $this->inputDesc,
            "inputType"        => $this->inputType,
            "validate"         => $this->validateSupport ? $this->validateSupport->build() : new \stdClass(),
            "customAttributes" => empty($this->customAttributes) ? new \stdClass() : $this->customAttributes,
            "relations"        => $this->relations,
            "value"            => $this->value,
            'meanType'         => $this->meanType,
            'projectId'        => $this->projectId,
        ];
    }

    public function __get($name)
    {
        // TODO: Implement __get() method.
        return $this->{$name};
    }
}

